
open Namespace_ast

let base_tab = "   "

let print_ast t =

	let ast_list_concat lst = 
		List.fold_left (^) "" lst in

	let ast_list_to_string func space lst = 
		ast_list_concat (List.map (fun e -> func (space ^ base_tab ) e) lst) in
		
	let rec sourceElement_to_string space = function
		| AStatement(stmt)	-> (statement_to_string space stmt)
		| ANamespace(stmt) -> namespace_to_string space stmt
		(*| AFunctionDeclaration(funcDec)	-> (functionDeclaration_to_string space funcDec) *) (* Modif #1 *)

	and program_to_string space prog = space ^ "Program (\n"
		^ (ast_list_to_string sourceElement_to_string space prog)
		^ space ^ ")\n"
	
	and formalParameterList_to_string space params =
		space ^ "Params (\n"
		^ (ast_list_to_string (fun space e -> space ^ e ^ "\n") space params)
		^ space ^ ")\n"

	and functionDeclaration_to_string space (is_private, is_meta,is_inline, identifier,params,body) = space 
		^ (if is_private then "Private " else "") 
		^ (if is_meta then "Meta " else "") 
		^ (if is_inline then "Inline " else "") ^ "FunctionDeclaration (\n"
		^ (identifier_to_string (space ^ base_tab) identifier)
		^ (formalParameterList_to_string (space ^ base_tab) params)
		^ (functionBody_to_string (space ^ base_tab) body)
		^ space ^ ")\n"
		
	and classStatement_to_string space (is_private,is_meta,identifier,extends,classElements) = space 
		^ (if is_private then "Private " else "") 
		^ (if is_meta then "Meta " else "")
		^ "ClassStatement (\n"
		^ (match extends with
			| None -> ""
			| Some idents -> 
				(match idents with
					| [] -> ""
					| a::idents ->
				space ^ base_tab ^ "Extends " ^ (List.fold_left (fun s i -> s ^ "." ^ i) a idents))
				)
		^ (identifier_to_string (space ^ base_tab) identifier)
		^ (ast_list_to_string classElement_to_string space classElements)
		^ space ^ ")\n"
	
	and classElement_to_string space = function
		| ACVariableStatement(variableStatement) -> variableStatement_to_string space variableStatement
		| ACConstStatement(constStatement) -> constStatement_to_string space constStatement
		| ACFuncDeclaration(functionDeclaration) -> functionDeclaration_to_string space functionDeclaration

	and functionExpression_to_string space (is_inline, identifier,params,body) = space ^ (if is_inline then "Inline " else "") ^ "FunctionExpression (\n"
		^ (match identifier with
			| None -> space ^ base_tab ^ "NoIdentifier\n"
			| Some identifier -> (identifier_to_string (space ^ base_tab) identifier)
		)
		^ (formalParameterList_to_string (space ^ base_tab) params)
		^ (functionBody_to_string (space ^ base_tab) body)
		^ space ^ ")\n"

	and functionBody_to_string space sourceElements =
		space ^ "FunctionBody (\n"
		^ (ast_list_to_string sourceElement_to_string space sourceElements)
		^ space ^ ")\n"

	and block_to_string space block = 
		space ^ "Block (\n"
		^ (ast_list_to_string statement_to_string space block)
		^ space ^ ")\n"

	and statement_to_string space = function
		| ABlock(block) -> block_to_string space block
		| AOperatorAssignment op -> operatorAssignment_to_string space op
		| AOperatorUnassignment op -> operatorUnassignment_to_string space op
		| AVariableStatement(variableStatement) -> variableStatement_to_string space variableStatement
		| AConstStatement(constStatement) -> constStatement_to_string space constStatement
		| AEmptyStatement -> space ^ "EmptyStatement\n"
		| AExpressionStatement(expressionStatement) -> expressionStatement_to_string space expressionStatement
		| AIfStatement(ifStatement) -> ifStatement_to_string space ifStatement
		| AFuncDeclaration(functionDeclaration) -> functionDeclaration_to_string space functionDeclaration
		| AClassStatement(classStatement) -> classStatement_to_string space classStatement
		| AIterationStatement(iterationStatement) -> iterationStatement_to_string space iterationStatement
		| AContinueStatement(continueStatement) -> continueStatement_to_string space continueStatement
		| ABreakStatement(breakStatement) -> breakStatement_to_string space breakStatement
		| AReturnStatement(returnStatement) -> returnStatement_to_string space returnStatement
		| AWithStatement(withStatement) -> withStatement_to_string space withStatement
		| ALabelledStatement(labelledStatement) -> labelledStatement_to_string space labelledStatement
		| ASwitchStatement(switchStatement) -> switchStatement_to_string space switchStatement
		| AThrowStatement(throwStatement) -> throwStatement_to_string space throwStatement
		| ATryStatement(tryStatement) -> tryStatement_to_string space tryStatement
		| ADebuggerStatement -> space ^ "DebuggerStatement\n"
	
	and namespace_to_string space (idents,body) = space ^ "Namespace (\n"
		^ space ^ base_tab ^ "Name : " ^ (List.fold_left (fun s i -> s ^ "." ^ i) "" idents) ^ "\n"
		^ (functionBody_to_string (space ^ base_tab) body)
		^ space ^ ")\n"

	and operatorAssignment_to_string space (ident,expr) = 
		space ^ "OperatorAssignment (\n"
		^ (identifier_to_string (space ^ base_tab)) ident
		^ (assignmentExpression_to_string (space ^ base_tab)) expr
		^ space ^ ")\n"
		
	and operatorUnassignment_to_string space ident = 
		space ^ "OperatorUnassignment (\n"
		^ (identifier_to_string (space ^ base_tab)) ident
		^ space ^ ")\n"

	and variableStatement_to_string space (is_private, is_meta, stmt) = space 
		^ (if is_private then "Private " else "")
		^ (if is_meta then "Meta " else "")
		^ "VariableStatement (\n"
		^ (ast_list_to_string (fun space e -> (variableDeclaration_to_string space e) ^ "\n" ) space stmt)
		^ space ^ ")\n"

	and constStatement_to_string space (is_private, is_meta, stmt) = space 
		^ (if is_private then "Private " else "")
		^ (if is_meta then "Meta " else "")
		^ "ConstStatement (\n"
		^ (ast_list_to_string (fun space e -> (variableDeclaration_to_string space e) ^ "\n" ) space stmt)
		^ space ^ ")\n"

	and variableDeclaration_to_string space (ident,init) = 
		space ^ "VariableDeclaration (\n"
		^ (identifier_to_string (space ^ base_tab)) ident
		^ (match init with
			| None -> space ^ base_tab ^ "NoInitializer\n"
			| Some init -> (initializer_to_string (space ^ base_tab)) init
			)
		^ space ^ ")\n"

	and initializer_to_string space init = 
		space ^ "Initializer (\n"
		^ (assignmentExpression_to_string (space ^ base_tab)) init
		^ space ^ ")\n"
		
	and identifier_to_string space ident = 
		space ^ "Identifier : " ^ ident ^ "\n"

	and expressionStatement_to_string space stmt = 
		expression_to_string space stmt

	and ifStatement_to_string space = function
		| AIfElse(expr, stmt1, stmt2) -> space ^ "IfElse (\n"
			^ (expression_to_string (space ^ base_tab) expr)
			^ (statement_to_string (space ^ base_tab) stmt1)
			^ (statement_to_string (space ^ base_tab) stmt2)
			^ space ^ ")\n"
		| AIf(expr, stmt) -> space ^ "If (\n"
			^ (expression_to_string (space ^ base_tab) expr)
			^ (statement_to_string (space ^ base_tab) stmt)
			^ space ^ ")\n"

	and iterationStatement_to_string space = function
		| ADoWhile(stmt, expr) -> space ^ "DoWhile (\n"
			^ (statement_to_string (space ^ base_tab) stmt)
			^ (expression_to_string (space ^ base_tab) expr)
			^ space ^ ")\n"
		| AWhile(expr, stmt) -> space ^ "While (\n"
			^ (expression_to_string (space ^ base_tab) expr)
			^ (statement_to_string (space ^ base_tab) stmt)
			^ space ^ ")\n"
		| AFor(expr1, expr2, expr3, stmt) -> "For (\n"
			^ (match expr1 with
				| None -> space ^ "NoFirstExpression\n"
				| Some expr1 -> (expression_to_string (space ^ base_tab) expr1)
				)
			^ (match expr2 with
				| None -> space ^ "NoSecondExpression\n"
				| Some expr2 -> (expression_to_string (space ^ base_tab)  expr2)
				)
			^ (match expr3 with
				| None -> space ^ "NoThirdExpression\n"
				| Some expr3 -> (expression_to_string (space ^ base_tab) expr3)
				)
			^ (statement_to_string (space ^ base_tab) stmt)
			^ space ^ ")\n"
		| AForVar(is_meta, varDecl, expr1, expr2, stmt) -> "ForVar (\n"
			^ space ^ base_tab ^ (if is_meta then "Meta " else "") ^ "VarDeclList (\n" 
			^ (variableDeclarationList_to_string (space ^ base_tab ^ base_tab) varDecl)
			^ space ^ base_tab ^ ")\n"
			^ (match expr1 with
				| None -> space ^ "NoFirstExpression\n"
				| Some expr1 -> (expression_to_string (space ^ base_tab) expr1)
				)
			^ (match expr2 with
				| None -> space ^ "NoSecondExpression\n"
				| Some expr2 -> (expression_to_string (space ^ base_tab) expr2)
				)
			^ (statement_to_string (space ^ base_tab) stmt)
			^ space ^ ")\n"
		| AForIn(lhsExpr, expr, stmt) -> "ForIn (\n"
			^ (leftHandSideExpression_to_string (space ^ base_tab) lhsExpr)
			^ (expression_to_string (space ^ base_tab) expr)
			^ (statement_to_string (space ^ base_tab) stmt)
			^ space ^ ")\n"
		| AForVarIn(is_meta, varDecl, expr, stmt) -> "ForVarIn (\n"
			^ space ^ base_tab ^ (if is_meta then "Meta " else "") ^ "VarDecl (\n" 
			^ (variableDeclaration_to_string (space ^ base_tab ^ base_tab) varDecl)
			^ space ^ base_tab ^ ")\n"
			^ (expression_to_string (space ^ base_tab) expr)
			^ (statement_to_string (space ^ base_tab) stmt)
			^ space ^ ")\n"
	
	and variableDeclarationList_to_string space decls = space ^ "VarDeclList (\n"
		^ (ast_list_to_string variableDeclaration_to_string space decls)
		^ space ^ ")\n"

	and continueStatement_to_string space = function
		| None -> space ^ "ContinueStatement\n"
		| Some stmt -> space ^ "ContinueStatement (" ^ stmt ^ ")\n"

	and breakStatement_to_string space = function
		| None -> space ^ "BreakStatement\n"
		| Some stmt -> space ^ "BreakStatement (" ^ stmt ^ ")\n"

	and returnStatement_to_string space = function
		| None -> space ^ "ReturnStatement\n"
		| Some expr -> space ^ "ReturnStatement (\n"
		^ (expression_to_string (space ^ base_tab) expr)
		^ space ^ ")\n"

	and withStatement_to_string space (expr,stmt) = space ^ "WithStatement (\n"
		^ (expression_to_string (space ^ base_tab) expr)
		^ (statement_to_string (space ^ base_tab) stmt)
		^ space ^ ")\n"

	and switchStatement_to_string space (expr,caseBlock) = space ^ "SwitchStatement (\n"
		^ (expression_to_string (space ^ base_tab) expr)
		^ (caseBlock_to_string (space ^ base_tab) caseBlock)
		^ space ^ ")\n"

	and caseBlock_to_string space = function
		| ACasesNoDefault(caseClauses) -> space ^ "CasesNoDefault (\n"
			^ (caseClauseList_to_string (space ^ base_tab) caseClauses)
			^ space ^ ")\n"
		| ACasesDefault(caseClauses1, defaultClause, caseClauses2) -> space ^ "CasesDefault (\n"
			^ (caseClauseList_to_string (space ^ base_tab) caseClauses1)
			^ (defaultClause_to_string (space ^ base_tab) defaultClause)
			^ (caseClauseList_to_string (space ^ base_tab) caseClauses2)
			^ space ^ ")\n"
	
	and caseClauseList_to_string space clauses = space ^ "CaseClauses (\n"
		^ (ast_list_to_string caseClause_to_string space clauses)
		^ space ^ ")\n"

	and caseClause_to_string space (expr,stmts) = space ^ "CaseClause (\n"
		^ (expression_to_string (space ^ base_tab) expr)
		^ (ast_list_to_string statement_to_string space stmts)
		^ space ^ ")\n"

	and defaultClause_to_string space stmts = space ^ "DefaultClause (\n"
		^ (ast_list_to_string statement_to_string space stmts)
		^ space ^ ")\n"

	and labelledStatement_to_string space (ident,stmt) = space ^ "LabelledStatement (\n"
		^ (identifier_to_string (space ^ base_tab) ident)
		^ (statement_to_string (space ^ base_tab) stmt)
		^ space ^ ")\n" 

	and tryStatement_to_string space = function
		| ATryCatch(block, catch) -> space ^ "TryCatch (\n"
			^ (block_to_string (space ^ base_tab) block)
			^ (catch_to_string (space ^ base_tab) catch)
			^ space ^ ")\n"
		| ATryFinally(block,finally) -> space ^ "TryFinally (\n"
			^ (block_to_string (space ^ base_tab) block)
			^ (finally_to_string (space ^ base_tab) finally)
			^ space ^ ")\n"
		| ATryCatchFinally(block, catch, finally) -> space ^ "TryCatchFinally (\n"
			^ (block_to_string (space ^ base_tab) block)
			^ (catch_to_string (space ^ base_tab) catch)
			^ (finally_to_string (space ^ base_tab) finally)
			^ space ^ ")\n"

	and catch_to_string space (ident,block) = space ^ "Catch (\n"
		^ (identifier_to_string (space ^ base_tab) ident)
		^ (block_to_string (space ^ base_tab) block)
		^ space ^ ")\n"

	and finally_to_string space block = space ^ "Finally (\n"
		^ (block_to_string (space ^ base_tab) block)
		^ space ^ ")\n"

	and throwStatement_to_string space expr = space ^ "Throw (\n"
		^ (expression_to_string (space ^ base_tab) expr)
		^ space ^ ")\n"

	and literal_to_string space = function
		| ANull -> space ^ "Null\n"
		| ABooleanLiteral(boolean) -> space ^ "Boolean : " ^ (if boolean then "true" else "false") ^ "\n"
		| ALitNumericLiteral(numeric) -> space ^ "Numeric : " ^ numeric ^ "\n"
		| ALitStringLiteral(str) -> space ^ "String : " ^ str ^ "\n"
		| ARegularExpressionLiteral(regularExpression) -> 
			(regularExpression_to_string space regularExpression)

	and regularExpression_to_string space (str1,str2) = space ^ "Regex (\n"
		^ space ^ base_tab ^ "Expr : " ^ str1 ^ "\n"
		^ space ^ base_tab ^ "Flags : " ^ str2 ^ "\n"
		^ space ^ ")\n"

	and primaryExpression_to_string space = function
		| AThis -> space ^ "This\n"
		| AIdentifier(ident) -> (identifier_to_string space ident)
		| ALiteral(literal) -> (literal_to_string space literal)
		| AArrayLiteral(arrayLiteral) -> (arrayLiteral_to_string space arrayLiteral)
		| AObjectLiteral(objectLiteral) -> (objectLiteral_to_string space objectLiteral)
		| AExpression(expr) -> (expression_to_string space expr)

	and arrayLiteral_to_string space = function
		| AElisions(elisions) -> (elisionList_to_string space elisions)
		| AElements(elementList) -> (elementList_to_string space elementList)
		| AElementsAndElisions(elementList, elisions) -> space ^ "ElementsAndElisions (\n"
			^ (elementList_to_string (space ^ base_tab) elementList)
			^ (elisionList_to_string (space ^ base_tab) elisions)
			^ space ^ ")\n"

	and elisionList_to_string space elisions = space ^ "Elisions (\n"
		^ (ast_list_to_string (fun space e -> ",") space elisions) ^ ")\n"

	and elementList_to_string space elements = space ^ "ElementList (\n"
		^ (ast_list_to_string element_to_string space elements)
		^ space ^ ")\n"

	and element_to_string space (elisions,expr) = space ^ "Element (\n"
		^ (elisionList_to_string (space ^ base_tab) elisions)
		^ (assignmentExpression_to_string (space ^ base_tab) expr)
		^ space ^ ")\n"

	and objectLiteral_to_string space propertyAssignments = space ^ "ObjectLiteral (\n"
		^ (ast_list_to_string propertyAssignment_to_string space propertyAssignments)
		^ space ^ ")\n"

	and propertyAssignment_to_string space = function
		| APropAssignment(propertyName, assignmentExpression) -> space ^ "PropAssignment (\n"
			^ (propertyName_to_string (space ^ base_tab) propertyName)
			^ (assignmentExpression_to_string (space ^ base_tab) assignmentExpression)
			^ space ^ ")\n"
		| APropGet(propertyName, functionBody) -> space ^ "PropGet (\n"
			^ (propertyName_to_string (space ^ base_tab) propertyName)
			^ (functionBody_to_string (space ^ base_tab) functionBody)
			^ space ^ ")\n"
		| APropSet(propertyName, identifiers, functionBody) -> space ^ "PropSet (\n"
			^ (propertyName_to_string (space ^ base_tab) propertyName)
			^ (identifierList_to_string (space ^ base_tab) identifiers)
			^ (functionBody_to_string (space ^ base_tab) functionBody)
			^ space ^ ")\n"
	
	and identifierList_to_string space idents = space ^ "Identifiers (\n"
		^ (ast_list_to_string identifier_to_string space idents)
		^ space ^ ")\n"

	and propertyName_to_string space = function
		| AIdentifierName(str) -> space ^ "IdentiferName : " ^ str ^ "\n"
		| AStringLiteral(str) -> space ^ "String : " ^ str ^ "\n"
		| ANumericLiteral(numeric) -> space ^ "Numeric : " ^ numeric ^ "\n"

	and memberExpression_to_string space = function
		| APrimaryExpr(primaryExpression) -> (primaryExpression_to_string space primaryExpression)
		| AFunctionExpr(functionExpression) -> (functionExpression_to_string space functionExpression)
		| AMemberBracketExpr(memberExpression, expression) -> space ^ "MemberBracketExpr (\n"
			^ (memberExpression_to_string (space ^ base_tab) memberExpression)
			^ (expression_to_string (space ^ base_tab) expression)
			^ space ^ ")\n"
		| AMemberDotExpr(memberExpression, str) -> space ^ "MemberDotExpr (\n"
			^ (memberExpression_to_string (space ^ base_tab) memberExpression)
			^ space ^ base_tab ^ "IdentifierName : " ^ str ^ "\n"
		| AMemberNewExpr(memberExpression, args) -> space ^ "MemberNewExpr (\n"
			^ (memberExpression_to_string (space ^ base_tab) memberExpression)
			^ (argumentList_to_string (space ^ base_tab) args)
			^ space ^ ")\n"

	and newExpression_to_string space = function
		| AMemberExpression(memberExpression) -> (memberExpression_to_string space memberExpression)
		| ANewMemberExpression(newExpression) -> space ^ "NewMemberExpression (\n"
			^ (newExpression_to_string (space ^ base_tab) newExpression)
			^ space ^ ")\n"

	and callExpression_to_string space = function
		| ACallMemberArgs(memberExpression, args) -> space ^ "CallMemberArgs (\n"
			^ (memberExpression_to_string (space ^ base_tab) memberExpression)
			^ (argumentList_to_string (space ^ base_tab) args)
			^ space ^ ")\n"
		| ACallExpressionArgs(callExpression, args) -> space ^ "CallExpressionArgs (\n"
			^ (callExpression_to_string (space ^ base_tab) callExpression)
			^ (argumentList_to_string (space ^ base_tab) args)
			^ space ^ ")\n"
		| ACallExpressionExpr(callExpression, expression) -> space ^ "CallExpressionExpr (\n"
			^ (callExpression_to_string (space ^ base_tab) callExpression)
			^ (expression_to_string (space ^ base_tab) expression)
			^ space ^ ")\n"
		| ACallExpressionIdent(callExpression, str) -> space ^ "CallExpressionIdent (\n"
			^ (callExpression_to_string (space ^ base_tab) callExpression)
			^ space ^ base_tab ^ "IdentifierName : " ^ str ^ "\n"
			^ space ^ ")\n"
	
	and argumentList_to_string space args = space ^ "Arguments (\n"
		^ (ast_list_to_string argument_to_string space args)
		^ space ^ ")\n"

	and argument_to_string space args = 
		assignmentExpression_to_string space args

	and leftHandSideExpression_to_string space = function
 		| ANewExpression(newExpression) -> (newExpression_to_string space newExpression)
		| ACallExpression(callExpression) -> (callExpression_to_string space callExpression)

	and postfixExpression_to_string space = function
		| ALeftHandSide(leftHandSideExpression) -> 
			(leftHandSideExpression_to_string space leftHandSideExpression)
		| ALeftHandSideOp(leftHandSideExpression, str) -> space ^ "LeftHandSideOp (\n"
			^ (leftHandSideExpression_to_string (space ^ base_tab) leftHandSideExpression)
			^ space ^ base_tab ^ "Operator : " ^ str ^ "\n"
			^ space ^ ")\n"

	and unaryExpression_to_string space = function
		| APostfixExpr(postfixExpression) -> (postfixExpression_to_string space postfixExpression)
		| AOpUnaryExpr(op,unaryExpression) -> space ^ "OpUnaryExpr (\n"
			^ space ^ base_tab ^ "Operator : " ^ op ^ "\n"
			^ (unaryExpression_to_string space unaryExpression)
			^ space ^ ")\n"

	and binaryExpression_to_string space = function
		| AUnaryExpr(unaryExpression) -> (unaryExpression_to_string space unaryExpression)
		| ABinaryExpr(op, binaryExpression1, binaryExpression2) -> space ^ "BinaryExpression (\n"
			^ space ^ base_tab ^ "Operator : " ^ op ^ "\n"
			^ (binaryExpression_to_string (space ^ base_tab) binaryExpression1)
			^ (binaryExpression_to_string (space ^ base_tab) binaryExpression2)
			^ space ^ ")\n"

	and conditionalExpression_to_string space = function
		| ACondBinaryExpr(binaryExpression) -> (binaryExpression_to_string space binaryExpression)
		| ACondTernaryExpr(binaryExpression, assignmentExpr1, assignmentExpr2) -> 
			space ^ "CondTernaryExpr (\n"
			^ (binaryExpression_to_string (space ^ base_tab) binaryExpression)
			^ (assignmentExpression_to_string (space ^ base_tab) assignmentExpr1)
			^ (assignmentExpression_to_string (space ^ base_tab) assignmentExpr2)
			^ space ^ ")\n"

	and assignmentExpression_to_string space = function
		| ACondExpr(conditionalExpression) -> (conditionalExpression_to_string space conditionalExpression)
		| AAssignOp(leftHandSideExpression, op, assignmentExpression) -> space ^ "AssignOp (\n"
			^ (leftHandSideExpression_to_string (space ^ base_tab) leftHandSideExpression)
			^ space ^ base_tab ^ "Operator : " ^ op ^ "\n"
			^ (assignmentExpression_to_string (space ^ base_tab) assignmentExpression)
			^ space ^ ")\n"

	and expression_to_string space exprs = space ^ "Expression (\n"
		^ (ast_list_to_string assignmentExpression_to_string space exprs)
		^ space ^ ")\n"

	in
		print_string (program_to_string "" t);
		print_newline ()
